﻿/*******************************************************************************
 *                                                                              *
 * Author    :  Angus Johnson                                                   *
 * Version   :  6.4.2                                                           *
 * Date      :  27 February 2017                                                *
 * Website   :  http://www.angusj.com                                           *
 * Copyright :  Angus Johnson 2010-2017                                         *
 *                                                                              *
 * License:                                                                     *
 * Use, modification & distribution is subject to Boost Software License Ver 1. *
 * http://www.boost.org/LICENSE_1_0.txt                                         *
 *                                                                              *
 * Attributions:                                                                *
 * The code in this library is an extension of Bala Vatti's clipping algorithm: *
 * "A generic solution to polygon clipping"                                     *
 * Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63.             *
 * http://portal.acm.org/citation.cfm?id=129906                                 *
 *                                                                              *
 * Computer graphics and geometric modeling: implementation and algorithms      *
 * By Max K. Agoston                                                            *
 * Springer; 1 edition (January 4, 2005)                                        *
 * http://books.google.com/books?q=vatti+clipping+agoston                       *
 *                                                                              *
 * See also:                                                                    *
 * "Polygon Offsetting by Computing Winding Numbers"                            *
 * Paper no. DETC2005-85513 pp. 565-575                                         *
 * ASME 2005 International Design Engineering Technical Conferences             *
 * and Computers and Information in Engineering Conference (IDETC/CIE2005)      *
 * September 24-28, 2005 , Long Beach, California, USA                          *
 * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf              *
 *                                                                              *
 *******************************************************************************/

#ifndef clipper_hpp
#define clipper_hpp

#define CLIPPER_VERSION "6.4.2"

// use_int32: When enabled 32bit ints are used instead of 64bit ints. This
// improve performance but coordinate values are limited to the range +/- 46340
//#define use_int32

// use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance.
//#define use_xyz

// use_lines: Enables line clipping. Adds a very minor cost to performance.
#define use_lines

// use_deprecated: Enables temporary support for the obsolete functions
//#define use_deprecated

#include <cstdlib>
#include <cstring>
#include <functional>
#include <list>
#include <ostream>
#include <queue>
#include <set>
#include <stdexcept>
#include <vector>

namespace ClipperLib {

enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
enum PolyType { ptSubject, ptClip };
// By far the most widely used winding rules for polygon filling are
// EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32)
// Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL)
// see http://glprogramming.com/red/chapter11.html
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };

#ifdef use_int32
typedef int cInt;
static cInt const loRange = 0x7FFF;
static cInt const hiRange = 0x7FFF;
#else
typedef signed long long cInt;
static cInt const loRange = 0x3FFFFFFF;
static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
typedef signed long long long64; // used by Int128 class
typedef unsigned long long ulong64;

#endif

struct IntPoint {
    cInt X;
    cInt Y;
#ifdef use_xyz
    cInt Z;
    IntPoint(cInt x = 0, cInt y = 0, cInt z = 0) : X(x), Y(y), Z(z){};
#else
    IntPoint(cInt x = 0, cInt y = 0) : X(x), Y(y){};
#endif

    friend inline bool operator==(const IntPoint &a, const IntPoint &b) { return a.X == b.X && a.Y == b.Y; }
    friend inline bool operator!=(const IntPoint &a, const IntPoint &b) { return a.X != b.X || a.Y != b.Y; }
};
//------------------------------------------------------------------------------

typedef std::vector<IntPoint> Path;
typedef std::vector<Path> Paths;

inline Path &operator<<(Path &poly, const IntPoint &p) {
    poly.push_back(p);
    return poly;
}
inline Paths &operator<<(Paths &polys, const Path &p) {
    polys.push_back(p);
    return polys;
}

std::ostream &operator<<(std::ostream &s, const IntPoint &p);
std::ostream &operator<<(std::ostream &s, const Path &p);
std::ostream &operator<<(std::ostream &s, const Paths &p);

struct DoublePoint {
    double X;
    double Y;
    DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {}
    DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {}
};
//------------------------------------------------------------------------------

#ifdef use_xyz
typedef void (*ZFillCallback)(IntPoint &e1bot, IntPoint &e1top, IntPoint &e2bot, IntPoint &e2top, IntPoint &pt);
#endif

enum InitOptions { ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4 };
enum JoinType { jtSquare, jtRound, jtMiter };
enum EndType { etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound };

class PolyNode;
typedef std::vector<PolyNode *> PolyNodes;

class PolyNode {
public:
    PolyNode();
    virtual ~PolyNode(){};
    Path Contour;
    PolyNodes Childs;
    PolyNode *Parent;
    PolyNode *GetNext() const;
    bool IsHole() const;
    bool IsOpen() const;
    int ChildCount() const;

private:
    // PolyNode& operator =(PolyNode& other);
    unsigned Index; // node index in Parent.Childs
    bool m_IsOpen;
    JoinType m_jointype;
    EndType m_endtype;
    PolyNode *GetNextSiblingUp() const;
    void AddChild(PolyNode &child);
    friend class Clipper; // to access Index
    friend class ClipperOffset;
};

class PolyTree : public PolyNode {
public:
    ~PolyTree() { Clear(); };
    PolyNode *GetFirst() const;
    void Clear();
    int Total() const;

private:
    // PolyTree& operator =(PolyTree& other);
    PolyNodes AllNodes;
    friend class Clipper; // to access AllNodes
};

bool Orientation(const Path &poly);
double Area(const Path &poly);
int PointInPolygon(const IntPoint &pt, const Path &path);

void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd);

void CleanPolygon(const Path &in_poly, Path &out_poly, double distance = 1.415);
void CleanPolygon(Path &poly, double distance = 1.415);
void CleanPolygons(const Paths &in_polys, Paths &out_polys, double distance = 1.415);
void CleanPolygons(Paths &polys, double distance = 1.415);

void MinkowskiSum(const Path &pattern, const Path &path, Paths &solution, bool pathIsClosed);
void MinkowskiSum(const Path &pattern, const Paths &paths, Paths &solution, bool pathIsClosed);
void MinkowskiDiff(const Path &poly1, const Path &poly2, Paths &solution);

void PolyTreeToPaths(const PolyTree &polytree, Paths &paths);
void ClosedPathsFromPolyTree(const PolyTree &polytree, Paths &paths);
void OpenPathsFromPolyTree(PolyTree &polytree, Paths &paths);

void ReversePath(Path &p);
void ReversePaths(Paths &p);

struct IntRect {
    cInt left;
    cInt top;
    cInt right;
    cInt bottom;
};

// enums that are used internally ...
enum EdgeSide { esLeft = 1, esRight = 2 };

// forward declarations (for stuff used internally) ...
struct TEdge;
struct IntersectNode;
struct LocalMinimum;
struct OutPt;
struct OutRec;
struct Join;

typedef std::vector<OutRec *> PolyOutList;
typedef std::vector<TEdge *> EdgeList;
typedef std::vector<Join *> JoinList;
typedef std::vector<IntersectNode *> IntersectList;

//------------------------------------------------------------------------------

// ClipperBase is the ancestor to the Clipper class. It should not be
// instantiated directly. This class simply abstracts the conversion of sets of
// polygon coordinates into edge objects that are stored in a LocalMinima list.
class ClipperBase {
public:
    ClipperBase();
    virtual ~ClipperBase();
    virtual bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
    bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed);
    virtual void Clear();
    IntRect GetBounds();
    bool PreserveCollinear() { return m_PreserveCollinear; };
    void PreserveCollinear(bool value) { m_PreserveCollinear = value; };

protected:
    void DisposeLocalMinimaList();
    TEdge *AddBoundsToLML(TEdge *e, bool IsClosed);
    virtual void Reset();
    TEdge *ProcessBound(TEdge *E, bool IsClockwise);
    void InsertScanbeam(const cInt Y);
    bool PopScanbeam(cInt &Y);
    bool LocalMinimaPending();
    bool PopLocalMinima(cInt Y, const LocalMinimum *&locMin);
    OutRec *CreateOutRec();
    void DisposeAllOutRecs();
    void DisposeOutRec(PolyOutList::size_type index);
    void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
    void DeleteFromAEL(TEdge *e);
    void UpdateEdgeIntoAEL(TEdge *&e);

    typedef std::vector<LocalMinimum> MinimaList;
    MinimaList::iterator m_CurrentLM;
    MinimaList m_MinimaList;

    bool m_UseFullRange;
    EdgeList m_edges;
    bool m_PreserveCollinear;
    bool m_HasOpenPaths;
    PolyOutList m_PolyOuts;
    TEdge *m_ActiveEdges;

    typedef std::priority_queue<cInt> ScanbeamList;
    ScanbeamList m_Scanbeam;
};
//------------------------------------------------------------------------------

class Clipper : public virtual ClipperBase {
public:
    Clipper(int initOptions = 0);
    bool Execute(ClipType clipType, Paths &solution, PolyFillType fillType = pftEvenOdd);
    bool Execute(ClipType clipType, Paths &solution, PolyFillType subjFillType, PolyFillType clipFillType);
    bool Execute(ClipType clipType, PolyTree &polytree, PolyFillType fillType = pftEvenOdd);
    bool Execute(ClipType clipType, PolyTree &polytree, PolyFillType subjFillType, PolyFillType clipFillType);
    bool ReverseSolution() { return m_ReverseOutput; };
    void ReverseSolution(bool value) { m_ReverseOutput = value; };
    bool StrictlySimple() { return m_StrictSimple; };
    void StrictlySimple(bool value) { m_StrictSimple = value; };
        // set the callback function for z value filling on intersections (otherwise Z is 0)
#ifdef use_xyz
    void ZFillFunction(ZFillCallback zFillFunc);
#endif
protected:
    virtual bool ExecuteInternal();

private:
    JoinList m_Joins;
    JoinList m_GhostJoins;
    IntersectList m_IntersectList;
    ClipType m_ClipType;
    typedef std::list<cInt> MaximaList;
    MaximaList m_Maxima;
    TEdge *m_SortedEdges;
    bool m_ExecuteLocked;
    PolyFillType m_ClipFillType;
    PolyFillType m_SubjFillType;
    bool m_ReverseOutput;
    bool m_UsingPolyTree;
    bool m_StrictSimple;
#ifdef use_xyz
    ZFillCallback m_ZFill; // custom callback
#endif
    void SetWindingCount(TEdge &edge);
    bool IsEvenOddFillType(const TEdge &edge) const;
    bool IsEvenOddAltFillType(const TEdge &edge) const;
    void InsertLocalMinimaIntoAEL(const cInt botY);
    void InsertEdgeIntoAEL(TEdge *edge, TEdge *startEdge);
    void AddEdgeToSEL(TEdge *edge);
    bool PopEdgeFromSEL(TEdge *&edge);
    void CopyAELToSEL();
    void DeleteFromSEL(TEdge *e);
    void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
    bool IsContributing(const TEdge &edge) const;
    bool IsTopHorz(const cInt XPos);
    void DoMaxima(TEdge *e);
    void ProcessHorizontals();
    void ProcessHorizontal(TEdge *horzEdge);
    void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
    OutPt *AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
    OutRec *GetOutRec(int idx);
    void AppendPolygon(TEdge *e1, TEdge *e2);
    void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt);
    OutPt *AddOutPt(TEdge *e, const IntPoint &pt);
    OutPt *GetLastOutPt(TEdge *e);
    bool ProcessIntersections(const cInt topY);
    void BuildIntersectList(const cInt topY);
    void ProcessIntersectList();
    void ProcessEdgesAtTopOfScanbeam(const cInt topY);
    void BuildResult(Paths &polys);
    void BuildResult2(PolyTree &polytree);
    void SetHoleState(TEdge *e, OutRec *outrec);
    void DisposeIntersectNodes();
    bool FixupIntersectionOrder();
    void FixupOutPolygon(OutRec &outrec);
    void FixupOutPolyline(OutRec &outrec);
    bool IsHole(TEdge *e);
    bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl);
    void FixHoleLinkage(OutRec &outrec);
    void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt);
    void ClearJoins();
    void ClearGhostJoins();
    void AddGhostJoin(OutPt *op, const IntPoint offPt);
    bool JoinPoints(Join *j, OutRec *outRec1, OutRec *outRec2);
    void JoinCommonEdges();
    void DoSimplePolygons();
    void FixupFirstLefts1(OutRec *OldOutRec, OutRec *NewOutRec);
    void FixupFirstLefts2(OutRec *InnerOutRec, OutRec *OuterOutRec);
    void FixupFirstLefts3(OutRec *OldOutRec, OutRec *NewOutRec);
#ifdef use_xyz
    void SetZ(IntPoint &pt, TEdge &e1, TEdge &e2);
#endif
};
//------------------------------------------------------------------------------

class ClipperOffset {
public:
    ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25);
    ~ClipperOffset();
    void AddPath(const Path &path, JoinType joinType, EndType endType);
    void AddPaths(const Paths &paths, JoinType joinType, EndType endType);
    void Execute(Paths &solution, double delta);
    void Execute(PolyTree &solution, double delta);
    void Clear();
    double MiterLimit;
    double ArcTolerance;

private:
    Paths m_destPolys;
    Path m_srcPoly;
    Path m_destPoly;
    std::vector<DoublePoint> m_normals;
    double m_delta, m_sinA, m_sin, m_cos;
    double m_miterLim, m_StepsPerRad;
    IntPoint m_lowest;
    PolyNode m_polyNodes;

    void FixOrientations();
    void DoOffset(double delta);
    void OffsetPoint(int j, int &k, JoinType jointype);
    void DoSquare(int j, int k);
    void DoMiter(int j, int k, double r);
    void DoRound(int j, int k);
};
//------------------------------------------------------------------------------

class clipperException : public std::exception {
public:
    clipperException(const char *description) : m_descr(description) {}
    virtual ~clipperException() throw() {}
    virtual const char *what() const throw() { return m_descr.c_str(); }

private:
    std::string m_descr;
};
//------------------------------------------------------------------------------

} // namespace ClipperLib

#endif // clipper_hpp
